package Types;

/**
 * Represents a complex number, consisting of a real and imaginary 
 * part. A Complex object is immutable, hence methods add, substract, 
 * multiply, etc return a new Complex object.
 * @author Cliff Laschet
 */
public class Complex {
    private double real;
    private double imaginary;
    
    /**
     * 
     */
    public Complex(){
        this.real = 0;
        this.imaginary = 0;
    }
    
    /**
     * 
     * @param real
     * @param imaginary 
     */
    public Complex(double real, double imaginary){
        this.real = real;
        this.imaginary = imaginary;
    }
    
    /**
     * 
     * @param number 
     */
    public Complex(Complex number){
        this.real = number.real;
        this.imaginary = number.imaginary;
    }
    
    /**
     * 
     * @return 
     */
    public double getRealPart(){
        return this.real;
    }
    
    /**
     * 
     * @return 
     */
    public double getImagPart(){
        return this.imaginary;
    }
    
    /**
     * 
     * @param real 
     */
    public void setRealPart(double real){
        this.real = real;
    }
    
    /**
     * 
     * @param imaginary 
     */
    public void setImagPart(double imaginary){
        this.imaginary = imaginary;
    }
    
    /**
     * Adds the given real number to the real part of the complex 
     * number.
     */
    public void addReal(double real){
        this.real += real;
    }
    
    /**
     * Adds the given imaginary number to the imaginary part of the 
     * complex 
     * number.
     * @param imaginary 
     */
    public void addImaginary(double imaginary){
        this.imaginary += imaginary;
    }
    
    /**
     * Multiplies the real part with the given scalar.
     * @param scalar 
     */
    public void multiplyReal(double scalar){
        this.real *= scalar;
    }
    
    /**
     * Multiplies the imaginary part with the given scalar.
     * @param scalar 
     */
    public void multiplyImaginary(double scalar){
        this.imaginary *= scalar;
    }
    
    /**
     * Adds the given complex number to this complex number.
     * @param number
     * @return 
     */
    public Complex add(Complex number){
        return new Complex(this.real + number.real, this.imaginary + 
                number.imaginary);
    }
    
    /**
     * Subtracts the given complex number from this complex number.
     * @param number
     * @return 
     */
    public Complex substract(Complex number){
        return new Complex(this.real - number.real, this.imaginary - 
                number.imaginary);
    }
    
    /**
     * Multiplies the given complex number with this complex number.
     * @param number
     * @return 
     */
    public Complex multiply(Complex number){
        return new Complex(this.real * number.real - this.imaginary * 
                number.imaginary, this.real * number.imaginary +
                this.imaginary * number.real);
    }
    
    /**
     * Multiplies this complex number by the given scalar.
     * @param scalar
     * @return 
     */
    public Complex multiply(double scalar){
        return new Complex(this.real * scalar, this.imaginary * scalar);
    }
    
    /**
     * Divides this complex number by the given complex number.
     * @param number
     * @return 
     */
    public Complex divide(Complex number){
        return this.multiply(number.conjugate().divide(
                number.real * number.real + number.imaginary *
                number.imaginary));
    }
    
    /**
     * Divides the complex number by the given scalar.
     * @param scalar
     * @return 
     */
    public Complex divide(double scalar){
        return this.multiply(1.0 / scalar);
    }
    
    /**
     * Creates the conjugate complex number of this complex number.
     * @return 
     */
    public Complex conjugate(){
        return new Complex(this.real, -this.imaginary);
    }
    
    /**
     * Returns the magnitude of the polar coordinate that represents
     * this complex number.
     * @return 
     */
    public double getMagnitude(){
        return Math.sqrt(this.real * this.real + this.imaginary *
                this.imaginary);
    }
    
    /**
     * Returns the angle of the polar coordinate that represents
     * this complex number.
     * @return 
     */
    public double getAngle(){
        if(this.real == 0 && this.imaginary == 0) return 0;
        double theta = Math.toDegrees(Math.atan(this.imaginary / 
                this.real));
        if(this.real >= 0 && this.imaginary >= 0) return theta;
        if(this.real <= 0 && this.imaginary >= 0) return 180 - theta;
        if(this.real <= 0 && this.imaginary <= 0) return 180 + theta;
        if(this.real >= 0 && this.imaginary <= 0) return 360 - theta;
        return Math.toDegrees(Math.atan(this.imaginary / this.real));
    }
    
    /**
     * 
     * @return 
     */
    public double[] toArray(){
        return new double[]{this.real, this.imaginary};
    }
}
